package net.starwifi.duobao.entity;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

import javax.persistence.*;
import javax.validation.Valid;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.util.*;

/**
 * 订单
 * - 3.0话费充值B币
 * - 红包转账
 * - 合作商商品购买
 * - 合作商理财产品购买
 *
 * Created by Administrator on 2015/9/17.
 */
@Entity
@Table(name = "duob_order")
@SequenceGenerator(name = "sequenceGenerator", sequenceName = "duob_order_sequence")
public class Order extends BaseEntity{

    private static final long serialVersionUID = 8370942500343156156L;

    /** 订单名称分隔符 */
    private static final String NAME_SEPARATOR = " ";

    /** 订单编号 */
    private String sn;

    /** 产品名称 */
    private String productName;

    /** 订单类型 （0充值，1转账，2购物，3理财）*/
    private int orderType;

    /** 订单状态（0已确认，1已完成，2已取消）*/
    private int orderStatus;

    /** 支付状态（0未支付，1已支付，2已退款,3部分支付,4部分退款）*/
    private int paymentStatus;

    /** 配送状态 （0未发货，1已发货，2已退货）*/
    private int shippingStatus;

    /** 支付手续费 */
    private BigDecimal fee;

    /** 运费 */
    private BigDecimal freight;

    /** 调整金额 */
    private BigDecimal offsetAmount;

    /** 已付金额 */
    private BigDecimal amountPaid;

    /** 赠送积分 */
    private Long point;

    /** 收货人 */
    private String consignee;

    /** 地区名称 */
    private String areaName;

    /** 地址 */
    private String address;

    /** 邮编 */
    private String zipCode;

    /** 电话 */
    private String phone;

    /** 到期时间 */
    private Date expire;

    /** 锁定到期时间 */
    private Date lockExpire;


    /** 是否开据发票 */
    private Boolean isInvoice;

    /** 发票抬头 */
    private String invoiceTitle;

    /** 税金 */
    private BigDecimal tax;

    /** 附言 */
    private String memo;

    /** 促销 */
    private String promotion;

    /** 是否已分配库存 */
    private Boolean isAllocatedStock;

    /** 支付方式名称 */
    private String paymentMethodName;

    /** 配送方式名称 */
    private String shippingMethodName;

    /** 地区 */
    private Area area;

    /** 支付方式 */
    private PaymentMethod paymentMethod;

    /** 配送方式 */
    private ShippingMethod shippingMethod;

    /** 付款方ID */
    private Long memberId;

    /** 付款方名称 */
    private String memberName;

    /** 收款方ID */
    private Long memberTwoId;

    /** 收款方名称 */
    private String memberTwoName;

    /** 订单日志 */
    private Set<OrderLog> orderLogs = new HashSet<OrderLog>();

    /** 收款单 */
   // private Set<Payment> payments = new HashSet<Payment>();

    /** 订单项 */
    private List<OrderItem> orderItems = new ArrayList<OrderItem>();





    @JsonProperty
    @Pattern(regexp = "^[0-9a-zA-Z_-]+$")
    @Length(max = 100)
    @Column(nullable = false, unique = true, length = 100)
    public String getSn() {
        return sn;
    }

    public void setSn(String sn) {
        this.sn = sn;
    }


    @JsonProperty
    @NotNull(groups = Save.class)
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    public BigDecimal getFee() {
        return fee;
    }

    public void setFee(BigDecimal fee) {
        this.fee = fee;
    }

    @JsonProperty
    @NotNull(groups = Save.class)
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    public BigDecimal getFreight() {
        return freight;
    }

    public void setFreight(BigDecimal freight) {
        this.freight = freight;
    }


    @JsonProperty
    @NotNull(groups = Save.class)
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    public BigDecimal getOffsetAmount() {
        return offsetAmount;
    }

    public void setOffsetAmount(BigDecimal offsetAmount) {
        this.offsetAmount = offsetAmount;
    }


    @JsonProperty
    @Column
    public Long getPoint() {
        return point;
    }

    public void setPoint(Long point) {
        this.point = point;
    }

    @JsonProperty
    @Column
    public String getConsignee() {
        return consignee;
    }

    public void setConsignee(String consignee) {
        this.consignee = consignee;
    }

    @JsonProperty
    @Column
    public String getAreaName() {
        return areaName;
    }

    public void setAreaName(String areaName) {
        this.areaName = areaName;
    }

    @JsonProperty
    @Column
    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @JsonProperty
    @Column
    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    @JsonProperty
    @Column
    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @JsonProperty
    @Column
    public Boolean getIsInvoice() {
        return isInvoice;
    }

    public void setIsInvoice(Boolean isInvoice) {
        this.isInvoice = isInvoice;
    }

    @JsonProperty
    @Column
    public String getInvoiceTitle() {
        return invoiceTitle;
    }

    public void setInvoiceTitle(String invoiceTitle) {
        this.invoiceTitle = invoiceTitle;
    }

    @JsonProperty
    @Column
    public BigDecimal getTax() {
        return tax;
    }

    public void setTax(BigDecimal tax) {
        this.tax = tax;
    }

    @JsonProperty
    @Column
    public String getMemo() {
        return memo;
    }

    public void setMemo(String memo) {
        this.memo = memo;
    }

    /**
     * 获取地区
     *
     * @return 地区
     */
    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    public Area getArea() {
        return area;
    }

    /**
     * 设置地区
     *
     * @param area
     *            地区
     */
    public void setArea(Area area) {
        this.area = area;
    }

    /**
     * 获取配送方式名称
     *
     * @return 配送方式名称
     */
    @Column(nullable = false)
    public String getShippingMethodName() {
        return shippingMethodName;
    }

    /**
     * 设置配送方式名称
     *
     * @param shippingMethodName
     *            配送方式名称
     */
    public void setShippingMethodName(String shippingMethodName) {
        this.shippingMethodName = shippingMethodName;
    }

    /**
     * 获取配送方式
     *
     * @return 配送方式
     */
    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    public ShippingMethod getShippingMethod() {
        return shippingMethod;
    }

    /**
     * 设置配送方式
     *
     * @param shippingMethod
     *            配送方式
     */
    public void setShippingMethod(ShippingMethod shippingMethod) {
        this.shippingMethod = shippingMethod;
    }

    @JsonProperty
    @Column
    public String getPromotion() {
        return promotion;
    }

    public void setPromotion(String promotion) {
        this.promotion = promotion;
    }

    @JsonProperty
    @Column
    public Boolean getIsAllocatedStock() {
        return isAllocatedStock;
    }

    public void setIsAllocatedStock(Boolean isAllocatedStock) {
        this.isAllocatedStock = isAllocatedStock;
    }


    @OneToMany(mappedBy = "order", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
    @OrderBy("createDate asc")
    public Set<OrderLog> getOrderLogs() {
        return orderLogs;
    }

    public void setOrderLogs(Set<OrderLog> orderLogs) {
        this.orderLogs = orderLogs;
    }

/*    @OneToMany(mappedBy = "order", fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
    public Set<Payment> getPayments() {
        return payments;
    }

    public void setPayments(Set<Payment> payments) {
        this.payments = payments;
    }*/

    @JsonProperty
    @Column
    public int getOrderType() {
        return orderType;
    }

    public void setOrderType(int orderType) {
        this.orderType = orderType;
    }

    @JsonProperty
    @Column
    public int getOrderStatus() {
        return orderStatus;
    }

    public void setOrderStatus(int orderStatus) {
        this.orderStatus = orderStatus;
    }

    @JsonProperty
    @Column
    public int getPaymentStatus() {
        return paymentStatus;
    }

    public void setPaymentStatus(int paymentStatus) {
        this.paymentStatus = paymentStatus;
    }

    @JsonProperty
    @Column
    public int getShippingStatus() {
        return shippingStatus;
    }

    public void setShippingStatus(int shippingStatus) {
        this.shippingStatus = shippingStatus;
    }

    @JsonProperty
    @Column
    public Long getMemberId() {
        return memberId;
    }

    public void setMemberId(Long memberId) {
        this.memberId = memberId;
    }

    @JsonProperty
    @Column
    public String getMemberName() {
        return memberName;
    }

    public void setMemberName(String memberName) {
        this.memberName = memberName;
    }

    @JsonProperty
    @Column
    public Long getMemberTwoId() {
        return memberTwoId;
    }

    public void setMemberTwoId(Long memberTwoId) {
        this.memberTwoId = memberTwoId;
    }

    @JsonProperty
    @Column
    public String getMemberTwoName() {
        return memberTwoName;
    }

    public void setMemberTwoName(String memberTwoName) {
        this.memberTwoName = memberTwoName;
    }


    @JsonProperty
    @Column
    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }


    @NotNull
    @ManyToOne
    public PaymentMethod getPaymentMethod() {
        return paymentMethod;
    }

    public void setPaymentMethod(PaymentMethod paymentMethod) {
        this.paymentMethod = paymentMethod;
    }

    @JsonProperty
    @Column
    public String getPaymentMethodName() {
        return paymentMethodName;
    }

    public void setPaymentMethodName(String paymentMethodName) {
        this.paymentMethodName = paymentMethodName;
    }


    /**
     * 获取到期时间
     *
     * @return 到期时间
     */
    public Date getExpire() {
        return expire;
    }

    /**
     * 设置到期时间
     *
     * @param expire
     *            到期时间
     */
    public void setExpire(Date expire) {
        this.expire = expire;
    }

    /**
     * 获取锁定到期时间
     *
     * @return 锁定到期时间
     */
    public Date getLockExpire() {
        return lockExpire;
    }

    /**
     * 设置锁定到期时间
     *
     * @param lockExpire
     *            锁定到期时间
     */
    public void setLockExpire(Date lockExpire) {
        this.lockExpire = lockExpire;
    }
    /**
     * 获取订单项
     *
     * @return 订单项
     */
    @Valid
    @NotEmpty
    @OneToMany(mappedBy = "order", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @OrderBy("isGift asc")
    public List<OrderItem> getOrderItems() {
        return orderItems;
    }

    /**
     * 设置订单项
     *
     * @param orderItems
     *            订单项
     */
    public void setOrderItems(List<OrderItem> orderItems) {
        this.orderItems = orderItems;
    }


    /**
     * 是否已过期
     *
     * @return 是否已过期
     */
    @Transient
    public boolean isExpired() {
        return getExpire() != null && new Date().after(getExpire());
    }

    /**
     * 获取已付金额
     *
     * @return 已付金额
     */
    @Column(nullable = false, precision = 21, scale = 6)
    public BigDecimal getAmountPaid() {
        return amountPaid;
    }

    /**
     * 设置已付金额
     *
     * @param amountPaid
     *            已付金额
     */
    public void setAmountPaid(BigDecimal amountPaid) {
        this.amountPaid = amountPaid;
    }

    /**
     * 获取订单名称
     *
     * @return 订单名称
     */
    @Transient
    public String getName() {
        StringBuffer name = new StringBuffer();
        if (getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && orderItem.getFullName() != null) {
                    name.append(NAME_SEPARATOR).append(orderItem.getFullName());
                }
            }
            if (name.length() > 0) {
                name.deleteCharAt(0);
            }
        }
        return name.toString();
    }

    /**
     * 获取商品价格
     *
     * @return 商品价格
     */
    @Transient
    public BigDecimal getPrice() {
        BigDecimal price = new BigDecimal(0);
        if (getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && orderItem.getSubtotal() != null) {
                    price = price.add(orderItem.getSubtotal());
                }
            }
        }
        return price;
    }


    /**
     * 获取订单金额
     *
     * @return 订单金额
     */
    @Transient
    public BigDecimal getAmount() {
        BigDecimal amount = getPrice();
        if (getFee() != null) {
            amount = amount.add(getFee());
        }
        if (getFreight() != null) {
            amount = amount.add(getFreight());
        }
        if (getOffsetAmount() != null) {
            amount = amount.add(getOffsetAmount());
        }
        if (getTax() != null) {
            amount = amount.add(getTax());
        }
        return amount.compareTo(new BigDecimal(0)) > 0 ? amount : new BigDecimal(0);
    }

    /**
     * 获取应付金额
     *
     * @return 应付金额
     */
    @Transient
    public BigDecimal getAmountPayable() {
        BigDecimal amountPayable = getAmount().subtract(getAmountPaid());
        return amountPayable.compareTo(new BigDecimal(0)) > 0 ? amountPayable : new BigDecimal(0);
    }


    /**
     * 获取订单项
     *
     * @param sn
     *            商品编号
     * @return 订单项
     */
    @Transient
    public OrderItem getOrderItem(String sn) {
        if (sn != null && getOrderItems() != null) {
            for (OrderItem orderItem : getOrderItems()) {
                if (orderItem != null && sn.equalsIgnoreCase(orderItem.getSn())) {
                    return orderItem;
                }
            }
        }
        return null;
    }

    /**
     * 持久化前处理
     */
    @PrePersist
    public void prePersist() {
        if (getPaymentMethod() != null) {
            setPaymentMethodName(getPaymentMethod().getName());
        }
    }

    /**
     * 更新前处理
     */
    @PreUpdate
    public void preUpdate() {
        if (getPaymentMethod() != null) {
            setPaymentMethodName(getPaymentMethod().getName());
        }
    }


}
